package com.dev.toolkit.service.impl;

import com.dev.toolkit.common.util.StrUtil2;
import com.dev.toolkit.model.ColumnModel;
import com.dev.toolkit.model.TableModel;
import com.dev.toolkit.service.IDataBaseMetaDataService;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * @author ZhuYouBin
 * @version 1.0.0
 * @date 2024/4/30 18:37
 * @description 数据库元数据信息服务
 */
@Service
public class DataBaseMetaDataService implements IDataBaseMetaDataService {
    private static final Logger logger = LoggerFactory.getLogger(DataBaseMetaDataService.class);
    @Resource
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public List<TableModel> getTableModelList(String databaseName, String... tableNames) {
        List<TableModel> tableModelList = new ArrayList<>();
        try {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            Connection connection = sqlSession.getConnection();
            DatabaseMetaData meta = connection.getMetaData();
            if (StrUtil2.isEmpty(databaseName)) {
                // 获取当前连接的数据库名称
                databaseName = StrUtil2.getDataBaseName(meta.getURL());
                logger.info("当前连接的数据库名称是:{}", databaseName);
            }
            if (tableNames == null || tableNames.length == 0) {
                // 百分号 % 表示获取所有表
                getTableModel(meta, databaseName, "%", tableModelList);
            } else {
                for (String tableName : tableNames) {
                    getTableModel(meta, databaseName, StrUtil2.ifEmptyToDefault(tableName, "%"), tableModelList);
                }
            }
            connection.close();
            sqlSession.close();
        } catch (Exception e) {
            logger.error("获取数据库元数据信息失败:", e);
        }
        return tableModelList;
    }

    /**
     * 获取数据表结构信息
     */
    private void getTableModel(DatabaseMetaData meta, String databaseName, String tableName, List<TableModel> tableModelList) throws SQLException {
        ResultSet rs = meta.getTables(databaseName, null, tableName, new String[]{"TABLE"});
        while (rs.next()) {
            // 1、获取数据表的元数据信息
            TableModel tableModel = new TableModel();
            tableModel.setDatabaseName(rs.getString("TABLE_CAT"));
            tableModel.setTableSpace(rs.getString("TABLE_SCHEM"));
            tableModel.setTableName(rs.getString("TABLE_NAME"));
            tableModel.setTableType(rs.getString("TABLE_TYPE"));
            tableModel.setTableRemark(rs.getString("REMARKS"));
            // 2、获取数据表的主键
            rs = meta.getPrimaryKeys(databaseName, null, tableName);
            Set<String> primaryKeySet = new HashSet<>();
            while (rs.next()) {
                primaryKeySet.add(rs.getString("COLUMN_NAME"));
            }
            // 3、获取数据表的列字段元数据信息
            rs = meta.getColumns(databaseName, null, tableName, null);
            tableModel.setColumnModelList(getColumnModel(rs, primaryKeySet));
            tableModelList.add(tableModel);
        }
    }

    /**
     * 获取数据表的列字段元数据信息
     */
    private static List<ColumnModel> getColumnModel(ResultSet rs, Set<String> primaryKeySet) throws SQLException {
        List<ColumnModel> columnModelList = new ArrayList<>();
        while (rs.next()) {
            ColumnModel columnModel = new ColumnModel();
            columnModel.setDatabaseName(rs.getString("TABLE_CAT"));
            columnModel.setTableSpace(rs.getString("TABLE_SCHEM"));
            columnModel.setTableName(rs.getString("TABLE_NAME"));
            columnModel.setColumnName(rs.getString("COLUMN_NAME"));
            columnModel.setTypeName(rs.getString("TYPE_NAME"));
            columnModel.setColumnRemark(rs.getString("REMARKS"));
            columnModel.setAutoIncrement(Objects.equals("YES", rs.getString("IS_AUTOINCREMENT")));
            columnModel.setPrimaryKey(primaryKeySet.contains(columnModel.getColumnName()));
            columnModelList.add(columnModel);
        }
        return columnModelList;
    }
}